﻿using AntdUI;
using System.Linq.Expressions;
using System.Reflection;
using WenAntdUI.Helps;

namespace WenAntdUI.Controls;

[ToolboxItem(true)]
public class ModelEdit : IControl
{

    #region 私有属性
    private readonly AntdUI.In.FlowLayoutPanel flow;
    private readonly System.Windows.Forms.Panel panel1;
    private readonly AntdUI.Button button_ok;
    private readonly AntdUI.Button button_cancel;
    private List<Control> modelControl = [];
    #endregion

    #region 构造函数

    public ModelEdit() : base()
    {
        flow = new AntdUI.In.FlowLayoutPanel()
        {
            Dock = DockStyle.Fill,
            AutoScroll = true,
            BackColor = Color.Transparent,
        };
        this.Controls.Add(flow);

        button_ok = new AntdUI.Button
        {
            Dock = DockStyle.Right,
            Size = new Size(120, 35),
            Text = "确定",
            Type = AntdUI.TTypeMini.Primary
        };
        button_cancel = new AntdUI.Button
        {
            Dock = DockStyle.Right,
            Name = "button1",
            Size = new Size(120, 35),
            Text = "取消",
            Type = AntdUI.TTypeMini.Error
        };

        panel1 = new System.Windows.Forms.Panel
        {
            Dock = DockStyle.Bottom,
            Height = 35,
            BackColor = Color.Transparent,
        };
        panel1.Controls.Add(button_ok);
        panel1.Controls.Add(button_cancel);
        this.Controls.Add(panel1);


        button_ok.Click += (s, e) => OkClick?.Invoke(this, Model);
        button_cancel.Click += (s, e) => CancelClick?.Invoke(this, Model);
    }


    #endregion

    #region 事件

    /// <summary>
    /// 取消按钮点击事件
    /// </summary>
    public event EventHandler<object> CancelClick;
    /// <summary>
    /// 确定按钮点击事件
    /// </summary>
    public event EventHandler<object> OkClick;


    #endregion

    #region 公有属性

    /// <summary>
    /// 按钮组显示
    /// </summary>
    public bool IsShowButton { get => panel1.Visible; set => panel1.Visible = value; }

    /// <summary>
    /// 是否显示取消按钮
    /// </summary>
    public bool IsShowButtonCancel { get => button_cancel.Visible; set => button_cancel.Visible = value; }

    /// <summary>
    /// 是否显示确定按钮
    /// </summary>
    public bool IsShowButtonOk { get => button_ok.Visible; set => button_ok.Visible = value; }

    /// <summary>
    /// 标签宽度
    /// </summary>
    [Description("标签宽度")]
    [Category("Wen")]
    [DefaultValue(100)]
    public int LableWidth { get; set; } = 100;

    /// <summary>
    /// 选项默认高度
    /// </summary>
    [Description("选项高度")]
    [Category("Wen")]
    [DefaultValue(35)]
    public int ItemHeight { get; set; } = 35;

    /// <summary>
    /// 边框宽度
    /// </summary>
    [Category("Wen"), Description("边框宽度"), DefaultValue(1f)]
    public float BorderWidth { get; set; } = 1f;
    #endregion


    //private BindingList<object> bindingModel;
    private BindingSource dataSource;
    private object model;

    public object Model
    {
        get => model;
        set
        {
            if (value == null) return;
            if (value != model)
            {
                if (dataSource == null)
                {
                    //bindingModel = [value];
                    dataSource = [];
                    dataSource.ListChanged += BindingModel_ListChanged;
                    dataSource.DataSourceChanged += (s, e) =>
                    {
                        foreach (Control item in this.modelControl)
                        {
                            foreach (Binding dataBinding in item.DataBindings)
                            {
                                dataBinding.ReadValue(); // 从模型读取最新值
                            }
                        }
                    };
                }
                //else
                //{
                //    //bindingModel[0] = value;
                //    dataSource.DataSource = value;
                //}
                ////this.model = bindingModel[0];

                dataSource.DataSource = value;
            }
        }
    }

    private void BindingModel_ListChanged(object? sender, ListChangedEventArgs e)
    {
        dataSource.ResumeBinding();
        //foreach (Control item in this.modelControl)
        //{
        //    foreach (Binding dataBinding in item.DataBindings)
        //    {
        //        dataBinding.ReadValue(); // 从模型读取最新值
        //    }
        //}
    }

    public ModelItemBuilder<TModel> GetItemBuilder<TModel>(TModel model)
    {
        this.Model = model;
        return new ModelItemBuilder<TModel>(this, model);
    }

    public class ModelItemBuilder<TModel>(ModelEdit owner, TModel model)
    {
        /// <summary>
        /// 添加数据行
        /// </summary>
        /// <param name="name">字段名称</param>
        /// <param name="content">自定义控件</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public ModelItemBuilder<TModel> Add(string name, string? lable = null, Control? content = null, Action<Control>? action = null)
        {
            var type = model.GetType() ?? throw new Exception("模型数据不能为null");
            var pinfo = type.GetProperty(name) ?? throw new Exception("获取字段失败");
            var propertyType = pinfo.PropertyType;

            var category = pinfo.GetCustomAttribute<DictAttribute>()?.Category;
            var title = lable ?? pinfo.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName ?? name;


            if (content != null)
            {
                content.DataBinding(owner.dataSource, "Value", name);
                action?.Invoke(content);
                AddControl(title, content, content.Height);
            }
            else if (category != null)
            {
                var control = new DictSelect(category);
                control.DataBinding(owner.dataSource, nameof(DictSelect.Value), name);
                action?.Invoke(control);
                AddControl(title, control);
            }
            else if (propertyType == typeof(bool))
            {
                var control = new AntdUI.Checkbox();
                control.DataBinding(owner.dataSource, nameof(Checkbox.Checked), name);
                action?.Invoke(control);
                AddControl(title, control);
            }
            else if (propertyType == typeof(int))
            {
                var control = new AntdUI.InputNumber();
                control.DataBinding(owner.dataSource, nameof(InputNumber.Value), name);
                action?.Invoke(control);
                AddControl(title, control);
            }
            else if (propertyType == typeof(Color))
            {
                var control = new AntdUI.ColorPicker()
                {
                    ShowText = true
                };
                control.DataBinding(owner.dataSource, nameof(ColorPicker.Value), name);
                action?.Invoke(control);
                AddControl(title, control);
            }
            else if (propertyType == typeof(Image))
            {
                var control = new PicFileSelect
                {
                    ImageWidth = 35,
                    Image = (Image)pinfo.GetValue(model)
                };
                control.ImageChanged += (s, e) =>
                {
                    pinfo.SetValue(model, e);
                };

                var bitmapDefault = new Bitmap(1, 1); // 默认值
                control.DataBinding(owner.dataSource, nameof(PicFileSelect.Image), name, f =>
                {
                    f.Value ??= bitmapDefault; // 将 null 转换为默认值
                }, p =>
                {
                    if (p.Value == bitmapDefault)
                        p.Value ??= null; // 确保模型属性可以接受 null
                });
                //var binding = new Binding(nameof(PicFileSelect.Image), model, name);
                //binding.Format += (s, e) =>
                //{
                //    e.Value ??= e.Value ?? new Bitmap(1, 1);// 将 null 转换为默认值
                //};
                //binding.Parse += (s, e) =>
                //{
                //    e.Value ??= null; // 确保模型属性可以接受 null
                //};
                //control.DataBindings.Add(binding);

                action?.Invoke(control);
                AddControl(title, control);
            }
            else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
            {
                var control = new AntdUI.DatePicker
                {
                    //Value = (DateTime?)pinfo.GetValue(model),
                    Format = "yyyy-MM-dd HH:mm:ss",
                };
                //control.DataBinding(model, nameof(DatePicker.Value), name);
                //control.ValueChanged += (s, e) =>
                //{
                //    pinfo.SetValue(model, e.Value);
                //};

                control.DataBinding(owner.dataSource, nameof(DatePicker.Text), name, f =>
                {
                    if ((f.Value as DateTime?)?.ToString("yyyy-MM-dd") == "0001-01-01")
                        f.Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    else
                        f.Value = ((f.Value ?? DateTime.Now) as DateTime?)?.ToString("yyyy-MM-dd HH:mm:ss");
                }, p =>
                {
                    p.Value = DateTime.TryParse(p.Value?.ToString(), out DateTime dateTime) ? dateTime : DateTime.Now;
                });


                action?.Invoke(control);
                AddControl(title, control);
            }
            else if (propertyType.IsEnum)
            {
                var es = propertyType.GetEnumItems();
                var control = new AntdUI.Select();
                control.Items.AddRange([.. es]);

                control.SelectedValue = es.Where(a => a.Value == pinfo.GetValue(model)?.ToString()).FirstOrDefault();
                control.SelectedValueChanged += (s, e) =>
                {
                    var value = ((EnumHelp.EnumItem?)e.Value)?.Value;
                    if (!string.IsNullOrWhiteSpace(value))
                        pinfo.SetValue(model, Enum.Parse(propertyType, value));
                };

                //绑定
                control.DataBinding(owner.dataSource, nameof(AntdUI.Select.Text), name);

                action?.Invoke(control);
                AddControl(title, control);
            }
            else
            {
                var control = new AntdUI.Input();
                control.DataBinding(owner.dataSource, nameof(Input.Text), name);
                action?.Invoke(control);
                AddControl(title, control);
            }
            return this;
        }

        /// <summary>
        /// 添加数据行
        /// </summary>
        /// <param name="expression">表达式</param>
        /// <param name="content">自定义控件</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public ModelItemBuilder<TModel> Add(Expression<Func<TModel, object?>> expression, string? lable = null, Control? content = null, Action<Control>? action = null)
        {
            var member = expression?.Body switch
            {
                MemberExpression m => m,
                UnaryExpression { Operand: MemberExpression m } => m,
                _ => null
            } ?? throw new Exception("数据获取失败");

            var name = member.Member.Name;

            return Add(name, lable, content, action);
        }

        /// <summary>
        /// 添加选项控件
        /// </summary>
        /// <param name="title"></param>
        /// <param name="control"></param>
        /// <param name="height"></param>
        private void AddControl(string title, Control control, int height = 0)
        {
            var h = height == 0 ? owner.ItemHeight : height;

            var group = new AntdUI.Panel()
            {
                Width = owner.flow.Width - 20,
                Height = h,
            };

            var lable = new AntdUI.Label()
            {
                Text = title,
                Width = owner.LableWidth,
                Dock = DockStyle.Left,
            };
            control.Dock = DockStyle.Fill;
            group.Controls.Add(control);
            group.Controls.Add(lable);

            owner.modelControl.Add(control);
            owner.flow.Controls.Add(group);
        }
    }

    #region 绘制   

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var g = e.Graphics.High();
        if (BorderWidth > 0)
            g.DrawBorderRound(this, BorderWidth);
    }

    #endregion
}
